package com.keyidea.jfxui.portal.view.server.test;

import com.keyidea.jfxui.core.config.context.SpringContextHelper;
import com.keyidea.jfxui.core.config.log.AsyncManager;
import com.keyidea.jfxui.core.config.redis.RedisUtil;
import com.keyidea.jfxui.core.server.utils.ByteUtils;
import com.keyidea.jfxui.core.server.utils.UdpClient;
import com.keyidea.jfxui.core.util.MemStorage;
import com.keyidea.jfxui.core.util.YamlUtil;
import de.saxsys.mvvmfx.FxmlView;
import de.saxsys.mvvmfx.InjectViewModel;
import javafx.application.Platform;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Alert;
import javafx.scene.control.Button;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextField;
import lombok.Data;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import java.net.SocketException;
import java.net.URL;
import java.text.NumberFormat;
import java.util.*;

@Slf4j
@Data
public class ComponentTestView implements FxmlView<ComponentTestViewModel>, Initializable {

    private final RedisUtil redisUtil = SpringContextHelper.getBean(RedisUtil.class);

    @InjectViewModel
    private ComponentTestViewModel componentTestViewModel;

    @FXML
    private TextField redisIpField;
    @FXML
    private TextField redisPortField;
    @FXML
    private TextField redisPasswordField;
    @FXML
    private TextField redisMessageField;
    @FXML
    private Button redisConfigSaveBtn;
    @FXML
    private Button redisMessageSendBtn;

    @FXML
    private TextField udpLocalIpField;
    @FXML
    private TextField udpLocalPortField;
    @FXML
    private TextField udpRemoteIpField;
    @FXML
    private TextField udpRemotePortField;
    @FXML
    private TextField redisKeyField;
    @FXML
    private TextField udpMessageField;

    @FXML
    private Button udpConnectBtn;

    @FXML
    private Button udpSendBtn;

    @FXML
    private Button redisSubscribeBtn;
    @FXML
    private Button redisCancelSubscribeBtn;
    @FXML
    private TextArea redisLogArea;

    @Override
    public void initialize(URL url, ResourceBundle resourceBundle) {
        NumberFormat numberInstance = NumberFormat.getNumberInstance();
        // 不展示千分位
        numberInstance.setGroupingUsed(false);
        redisIpField.textProperty().bindBidirectional(componentTestViewModel.getRedisIp());
        redisPortField.textProperty().bindBidirectional(componentTestViewModel.getRedisPort(), numberInstance);
        redisPasswordField.textProperty().bindBidirectional(componentTestViewModel.getRedisPassword());
        redisKeyField.textProperty().bindBidirectional(componentTestViewModel.getRedisKey());
        redisLogArea.textProperty().bindBidirectional(componentTestViewModel.getRedisLog());
        // 保存redis的配置信息
        redisConfigSaveBtn.setOnAction(event -> saveRedisConfig());
        // redis订阅
        redisSubscribeBtn.setOnAction(event -> subscribe());
        // redis取消订阅
        redisCancelSubscribeBtn.setOnAction(event -> subscribeCancel());
        // redis发送消息
        redisMessageSendBtn.setOnAction(event -> sendMessage());

        // udp链接
        udpConnectBtn.setOnAction(event -> connectUdp());
        // udp发送消息
        udpSendBtn.setOnAction(event -> sendUpdMessage());
        udpLocalIpField.textProperty().bindBidirectional(componentTestViewModel.getUdpLocalIp());
        udpLocalPortField.textProperty().bindBidirectional(componentTestViewModel.getUdpLocalPort(), numberInstance);
        udpRemoteIpField.textProperty().bindBidirectional(componentTestViewModel.getUdpRemoteIp());
        udpRemotePortField.textProperty().bindBidirectional(componentTestViewModel.getUdpRemotePort(), numberInstance);

        printLog();
    }

    private void appendRedisLogAreaText(List<String> list) {
        getRedisLogArea().appendText(String.join("，", list));
    }

    private void appendRedisLogArea() {
        List<String> list = new ArrayList<>();
        MemStorage.REDIS_MESSAGE_LIST.drainTo(list);
        if (!CollectionUtils.isEmpty(list)) {
            // redis消息不为空，析出全部输出到javaFX的redis消息池
            Platform.runLater(() -> appendRedisLogAreaText(list));
        }
    }

    @SneakyThrows
    private void printLog() {
        AsyncManager.me().addScheduledThreadPool(this.getClass().getSimpleName(), new TimerTask() {
            @Override
            public void run() {
                appendRedisLogArea();
            }
        });
    }

    private void sendMessage() {
        String key = redisKeyField.getText();
        String message = redisMessageField.getText();
        if (StringUtils.hasLength(key) && StringUtils.hasLength(message)) {
            redisUtil.publish(key, message);
            MemStorage.REDIS_MESSAGE_LIST.add(String.format("键名[%s]>>>%s %n", key, message));
        } else {
            Alert alert = new Alert(Alert.AlertType.INFORMATION);
            alert.setHeaderText(null);
            alert.setContentText("redis命令或者键名不能为空");
            alert.showAndWait();
        }
    }

    private void subscribe() {
        String channelName = redisKeyField.getText();
        if (StringUtils.hasLength(channelName)) {
            redisUtil.subscribe(channelName);
            MemStorage.REDIS_MESSAGE_LIST.add(String.format("已订阅[%s]%n", channelName));
        } else {
            Alert alert = new Alert(Alert.AlertType.INFORMATION);
            alert.setHeaderText(null);
            alert.setContentText("键名不能为空");
            alert.showAndWait();
        }
    }

    private void subscribeCancel() {
        String channelName = redisKeyField.getText();
        if (StringUtils.hasLength(channelName)) {
            redisUtil.unsubscribe(channelName);
            MemStorage.REDIS_MESSAGE_LIST.add(String.format("取消订阅[%s]%n", channelName));
        } else {
            Alert alert = new Alert(Alert.AlertType.INFORMATION);
            alert.setHeaderText(null);
            alert.setContentText("键名不能为空");
            alert.showAndWait();
        }
    }

    private void saveRedisConfig() {
        YamlUtil.setRedisValueStr("host", redisIpField.getText());
        YamlUtil.setRedisValueStr("port", redisPortField.getText());
        YamlUtil.setRedisValueStr("password", redisPasswordField.getText());
        YamlUtil.saveConfigFile(MemStorage.CONFIG_PROPERTIES, YamlUtil.PROPERTIES_PATH_DEFAULT);
    }

    private DatagramSocket localSocket;

    private void connectUdp() {
        try {
            localSocket = new DatagramSocket(new InetSocketAddress(udpLocalIpField.getText(), Integer.parseInt(udpLocalPortField.getText())));
        } catch (SocketException e) {
            throw new RuntimeException(e);
        }
    }

    private void sendUpdMessage() {
        if (Objects.isNull(localSocket)) {
            Alert alert = new Alert(Alert.AlertType.INFORMATION);
            alert.setHeaderText(null);
            alert.setContentText("请先点击链接");
            alert.showAndWait();
            return;
        }
        if (!StringUtils.hasLength(udpMessageField.getText())) {
            Alert alert = new Alert(Alert.AlertType.INFORMATION);
            alert.setHeaderText(null);
            alert.setContentText("发送消息不能为空");
            alert.showAndWait();
            return;
        }
        byte[] messageBytes = ByteUtils.hexToBytes(udpMessageField.getText());
        UdpClient.sendMsg(localSocket, udpRemoteIpField.getText(), Integer.parseInt(udpRemotePortField.getText()), messageBytes);
    }
}
